﻿using System.Collections.Concurrent;
using Basic.WxApiRemoteModel;
using Basic.WxCollect;
using Basic.WxExtendService.Interface;
using Basic.WxModel.PlatformBind;
using Basic.WxRemoteModel.EventMsg;
using LinqKit;
using WeDonekRpc.Client;
using WeDonekRpc.Client.Attr;
using WeDonekRpc.Client.Interface;
using WeDonekRpc.Client.Ioc;

namespace Basic.WxExtendService.Extend
{
    [ClassLifetimeAttr(ClassLifetimeType.SingleInstance)]
    internal class WxMerBindCacheService : IWxMerBindCacheService
    {
        private static readonly ConcurrentDictionary<string, string> _WxBind = new ConcurrentDictionary<string, string>();
        private static readonly ConcurrentDictionary<string, WxPlatformBindDto> _BindCache = new ConcurrentDictionary<string, WxPlatformBindDto>();

        public WxMerBindCacheService (IRouteService route)
        {
            route.AddRoute<WxMerBindCancel>("WxMerCancelBind", a =>
            {
                this._Clear(a.AppId, a.WxAppId);
            });
            route.AddRoute<RefreshWxMerBind>("RefreshWxMerBind", a =>
            {
                this._ClearBind(a.AppId, a.WxAppId);
            });
        }

        public string GetAvailableAppId (string wxAppId, WxPrower prower)
        {
            string key = wxAppId + "_" + ( (int)prower ).ToString();
            if (_WxBind.TryGetValue(key, out string appId))
            {
                return appId;
            }
            using (IocScope scope = RpcClient.Ioc.CreateScore())
            {
                IWxPlatformBindCollect service = scope.Resolve<IWxPlatformBindCollect>();
                appId = service.GetAvailableAppId(wxAppId, prower);
                _ = _WxBind.TryAdd(key, appId);
                return appId;
            }
        }
        public WxPlatformBindDto GetBind (string appId, string wxAppId)
        {
            string key = appId + "_" + wxAppId;
            if (_BindCache.TryGetValue(key, out WxPlatformBindDto bind))
            {
                return bind;
            }
            using (IocScope scope = RpcClient.Ioc.CreateScore())
            {
                IWxPlatformBindCollect service = scope.Resolve<IWxPlatformBindCollect>();
                bind = service.Get(appId, wxAppId);
                _ = _BindCache.TryAdd(key, bind);
                return bind;
            }
        }

        private void _Clear (string appId, string wxAppId)
        {
            string key = wxAppId + "_";
            string[] keys = _WxBind.Where(c => c.Key.StartsWith(key) && c.Value == appId).Select(c => c.Key).ToArray();
            if (keys.Length > 0)
            {
                keys.ForEach(c => _WxBind.TryRemove(key, out _));
            }
            key = appId + "_" + wxAppId;
            _ = _BindCache.TryRemove(key, out _);
        }
        private void _ClearBind (string appId, string wxAppId)
        {
            string key = appId + "_" + wxAppId;
            _ = _BindCache.TryRemove(key, out _);
        }
        public void SetRefreshToken (WxPlatformBindDto bind, string refresh_token)
        {
            if (bind.RefreshToken == refresh_token)
            {
                return;
            }
            using (IocScope scope = RpcClient.Ioc.CreateScore())
            {
                IWxPlatformBindCollect service = scope.Resolve<IWxPlatformBindCollect>();
                service.SetRefreshToken(bind, refresh_token);
                this._ClearBind(bind.AppId, bind.WxAppId);
            }
            new RefreshWxMerBind
            {
                AppId = bind.AppId,
                WxAppId = bind.WxAppId,
            }.Send();
        }

    }
}
